﻿using System;
using System.Text;
using System.Threading;
using System.Windows.Browser;
using System.Windows.Threading;

namespace CrmAttachmentImage
{
    internal static class Utility
    {
        private static Uri _serverUrl;
        private static FormTypes _formType;

        public enum AttributePrivilege
        {
            Read,
            Update,
            Create
        }

        public enum FormTypes
        {
            NotSet = -1,
            Undefined = 0,
            Create = 1,
            Update = 2,
            ReadOnly = 3,
            Disabled = 4,
            BulkEdit = 6
        }

        public static Uri ServerUrl
        {
            get { return _serverUrl ?? (_serverUrl = GetServerUrl()); }
        }

        static Utility()
        {
            _formType = FormTypes.NotSet;
        }

        public static FormTypes FormType
        {
            get
            {
                dynamic xrm = (ScriptObject)HtmlPage.Window.GetProperty("Xrm");
                var o = (double?)xrm.Page.ui.getFormType();
                if (o.HasValue)
                {
                    var d = o.Value;

                    var i = Convert.ToInt32(d);
                    if (i == 5) i = 0; //deprecated type
                    _formType = (FormTypes)i;
                }
                return _formType;
            }
        }

        public static bool AttributePriveledge(string fieldname, AttributePrivilege requiredPrivilege)
        {
            dynamic xrm = (ScriptObject)HtmlPage.Window.GetProperty("Xrm");
            var priv = (ScriptObject)xrm.Page.data.entity.attributes.get(fieldname).getUserPrivilege();

            //var attribute = (ScriptObject)XrmPageDataEntityAttributes.Invoke("get", fieldname.ToLower());
            //var priv = (ScriptObject)attribute.Invoke("getUserPrivilege");

            var strRequiredPrivilege = "can" + requiredPrivilege;
            return (bool)priv.GetProperty(strRequiredPrivilege);
        }

        /// <summary>
        ///   Combines a URI with a relative URI
        /// </summary>
        /// <param name = "baseUrl">Base (absolute) URI</param>
        /// <param name = "path">Relative URI that is to be used</param>
        /// <returns>Combined URI</returns>
        public static Uri CombineUrl(Uri baseUrl, string path)
        {
            if (null == baseUrl)
            {
                throw new ArgumentNullException("baseUrl");
            }

            if (string.IsNullOrEmpty(path))
            {
                return baseUrl;
            }

            var url = baseUrl.AbsoluteUri;
            var end = url.Length - 1;

            // Check if there is a '/' at the beginning of path
            if (url[end] == '/' && path[0] == '/')
            {
                url = url.Substring(0, end);
            }
            else if (url[end] != '/' && path[0] != '/')
            {
                url += '/';
            }

            // Create the combined URL
            return new Uri(url + path);
        }

        public static string ConvertToString(Exception exception)
        {
            var innerException = false;

            var sb = new StringBuilder();
            while (exception != null)
            {
                if (innerException)
                {
                    sb.Append("Inner Exception: ");
                }
                sb.AppendLine(exception.Message);
                sb.AppendLine(exception.StackTrace);

                innerException = true;
                exception = exception.InnerException;
            }

            return sb.ToString();
        }

        public static T GetEntityValue<T>(string fieldname, T defaultValue)
        {
            dynamic xrm = (ScriptObject)HtmlPage.Window.GetProperty("Xrm");
            return (T)xrm.Page.data.entity.attributes.get(fieldname).getValue();

            //if (XrmPageDataEntityAttributes == null)
            //{
            //    return defaultValue;
            //}
            //var attribute = (ScriptObject)XrmPageDataEntityAttributes.Invoke("get", fieldname.ToLower());
            //if (attribute == null) return defaultValue;
            //return (T)attribute.Invoke("getValue");
        }

        public static void SetEntityValue<T>(string fieldname, T value)
        {
            dynamic xrm = (ScriptObject)HtmlPage.Window.GetProperty("Xrm");
            xrm.Page.data.entity.attributes.get(fieldname).setValue(value);
            //var attribute = (ScriptObject)XrmPageDataEntityAttributes.Invoke("get", fieldname.ToLower());
            //attribute.Invoke("setValue", new object[] { value });
        }

        private static Uri GetServerUrl()
        {
            var pageUrl = HtmlPage.Document.DocumentUri.ToString();
            dynamic xrm = (ScriptObject)HtmlPage.Window.GetProperty("Xrm");
            var xrmServerUrl = (string)xrm.Page.context.getServerUrl();

            var urlA = pageUrl.Substring(0, xrmServerUrl.Length).ToLower();
            var urlB = xrmServerUrl.ToLower();

            string serverUrl;
            if (urlA == urlB)
            {
                serverUrl = xrmServerUrl;
            }
            else
            {
                // If they don't match it must be onPremise and the URL
                // could be different based on the host name.
                
                // On Premise is http or https://server/org/... so get that url...
                var slash1 = pageUrl.IndexOf('/', 10);
                var slash2 = pageUrl.IndexOf('/', slash1 + 1);
                serverUrl = pageUrl.Substring(0, slash2);
            }
            
            // Remove the trailing forwards slash returned by CRM Online
            // So that it is always consistent with CRM On Premises
            var end = serverUrl.Length - 1;
            if (serverUrl[end] == '/')
            {
                serverUrl = serverUrl.Substring(0, end);
            }

            return new Uri(serverUrl);
        }
    }
}